package main

import (
     "fmt"
     "log"
     "context"
     "go.mongodb.org/mongo-driver/bson"    //BOSN解析包
     "go.mongodb.org/mongo-driver/mongo"    //MongoDB的Go驱动包
     "go.mongodb.org/mongo-driver/mongo/options"
)

type People struct {
       Name string `json:"Name" bson:"Name"`
       Age  int `json:"Age" bson:"Age"`
}

func main() {
	clientDB := connectDB()
	collection := createCollection(clientDB)
	findDB(collection)
	findOneDB(collection, "ccc")
	findOneDBByNameAndAge(collection)
	findOneDBByNameOrAge(collection)
	disconnectDB(clientDB)
}

func connectDB() *mongo.Client {
     // Set client options
     clientOptions := options.Client().ApplyURI("mongodb://127.0.0.1:27017")
     // Connect to MongoDB, client 就是与 mongodb 的连接对象, 代表整个 mongo 数据库
     client, err := mongo.Connect(context.TODO(), clientOptions)
     if err != nil {
         log.Fatal(err)
     }   
     // Check the connection
     err = client.Ping(context.TODO(), nil)
     if err != nil {
         log.Fatal(err)
     }   
     fmt.Println("> Connected to MongoDB!")
     return client
}

func disconnectDB(clientDB *mongo.Client) {
     err := clientDB.Disconnect(context.TODO())
     if err != nil {
         log.Fatal(err)
     }
     fmt.Println("> Connection to MongoDB closed.")
 }

func createCollection(clientDB *mongo.Client) *mongo.Collection {
     // mongo 中可以有很多数据库 database，每个 database有很多 collection
     // collection 是要操作的数据集(相当于表), 
     // 此处指向的数据库是 test, 数据表是 col1
     collection := clientDB.Database("orcafs").Collection("col1")
     fmt.Println("create DB orcafs and table col1")
     return collection
}


// 没有找到也不会报错，因此要判断查询结果的个数
func findDB(collection *mongo.Collection) {
    // Passing bson.D{{}} as the filter matches all documents in the collection 
    record, err := collection.Find(context.TODO(), bson.D{{}})
    if err != nil {
        log.Fatal(err)
    }
    defer func() {
        if err := record.Close(context.TODO()); err != nil {
            log.Fatal(err)
        }
    }()

    allRecord := []People{}
    _ = record.All(context.TODO(), &allRecord) //也可以用 next
    for _, r := range allRecord {
        fmt.Println("find all db:", r)
    }
}

// 单条件查找一个，也存在查询多个的情况
func findOneDB(collection *mongo.Collection, name string) {
     var p People
     err := collection.FindOne(context.TODO(), bson.D{{"Name", name}}).Decode(&p)
     fmt.Println("FindOne return:", err)
     
     if err != nil {
         if err == mongo.ErrNoDocuments {
             // 根据指定条件无法找到，判断是否需要执行 insert 操作 
             log.Fatal(err)
         } else {
             log.Fatal(err)
         }
     }   
     fmt.Println(p)
}

// 多单条件查找一个，也存在查询多个的情况
func findOneDBByNameAndAge(collection *mongo.Collection) {
     var p People
	 filter := bson.D{
		{"$and", bson.A{
			bson.D{{"Age",3}},
			bson.D{{"Name", "ccc"}},
		}},
	 }
     err := collection.FindOne(context.TODO(), filter).Decode(&p)
     fmt.Println("FindOneByNameAndAge return:", err)
     
     if err != nil {
         if err == mongo.ErrNoDocuments {
             // 根据指定条件无法找到，判断是否需要执行 insert 操作 
             log.Fatal(err)
         } else {
             log.Fatal(err)
         }
     }   
     fmt.Println(p)
}

// 多单条件查找查询多个
func findOneDBByNameOrAge(collection *mongo.Collection) {
	 filter := bson.D{
		{"$or", bson.A{
			bson.D{{"Age", 10}},
			bson.D{{"Name", "ccc"}},
		}},
	 }
	 // 没找到不会报错，要判断返回个数
     record, err := collection.Find(context.TODO(), filter)
     fmt.Println("FindOneByNameOrAge return:", err)
     
     if err != nil {
        log.Fatal(err)
     }   

	defer func() {
         if err := record.Close(context.TODO()); err != nil {
             log.Fatal(err)
         }
     }()

     allRecord := []People{}
     _ = record.All(context.TODO(), &allRecord) //也可以用 next
     for _, r := range allRecord {
         fmt.Println(r)
     }
}

